#include "app_message.h"
#include "json/cJSON.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "log/log.h"

/**
 * 将二进制转换为字符串
 */
static char *app_message_hex2str(void *hex_ptr, size_t hex_len)
{
    char *str = (char *)malloc(hex_len * 2 + 1);
    if (!str)
    {
        return NULL;
    }
    unsigned char *temp_ptr = hex_ptr;
    for (size_t i = 0; i < hex_len; i++)
    {
        sprintf(str + i * 2, "%02X", temp_ptr[i]);
    }
    str[hex_len * 2] = '\0';
    return str;
    
}

static unsigned char app_message_hexChar2hex(char hex_char)
{
    if (hex_char >= '0' && hex_char <= '9')
    {
        return hex_char - '0';
    }
    else if (hex_char >= 'a' && hex_char <= 'f')
    {
        return hex_char - 'a' + 10;
    }
    else if (hex_char >= 'A' && hex_char <= 'F')
    {
        return hex_char - 'A' + 10;
    }
    else
    {
        log_error("Invalid hex char");
        return 0;
    }
}



/**
 * 将字符串转换为二进制
 */
static void app_message_str2hex(char *str,void *hex_ptr, size_t hex_len)
{
    unsigned char *temp_ptr = hex_ptr;
    for (size_t i = 0; i < hex_len; i++)
    {
        temp_ptr[i] = 0;
        //先处理str + 2*i,这一位存储的是temp_ptr[i]的高位
        temp_ptr[i] += app_message_hexChar2hex(str[2 * i]);
        temp_ptr[i] <<= 4;
        //再处理str + 2*i + 1,这一位存储的是temp_ptr[i]的低位
        temp_ptr[i] += app_message_hexChar2hex(str[2 * i + 1]);

    }
}

/**
 * 消息是由二进制组成，帧格式为：
 *  1.消息类型（1字节）
 *  2.消息ID的长度（2字节）
 *  3.消息内容的长度（1字节）
 *  4.消息ID，二进制（可变长度）
 *  5.消息内容，二进制（可变长度）
 */
Message *app_message_initFromBinary(void *data, size_t len)
{
    // 1.确保消息的长度大于3字节
    if (len <= 3)
    {
        log_warn("message length too short");
        return NULL;
    }

    // 2.申请message的内存
    Message *msg = (Message *)malloc(sizeof(Message));
    if (msg == NULL)
    {
        log_error("Not enough memory");
        goto MSG_ALLOC_FAIL;
    }
    memset(msg, 0, sizeof(Message));
    //3.读取类型，id长度和内容长度
    memcpy(&msg->type, data, 1);
    memcpy(&msg->id_len, data + 1, 1);
    memcpy(&msg->len, data + 2, 1);

    // 4.读取id和内容
    msg->id = malloc(msg->id_len);
    if (msg->id == NULL)
    {
        log_error("Not enough memory");
        goto ID_ALLOC_FAIL;
    }
    msg->data = malloc(msg->len);
    if (msg->data == NULL)
    {
        log_error("Not enough memory");
        goto DATA_ALLOC_FAIL;
    }
    memcpy(msg->id, data + 3, msg->id_len);
    memcpy(msg->data, data + 3 + msg->id_len, msg->len);

    log_debug("Message init from binary success");
    return msg;

DATA_ALLOC_FAIL:
    free(msg->id);

ID_ALLOC_FAIL:
    free(msg);

MSG_ALLOC_FAIL:
    return NULL;
}


/**
 * @brief 将一个json串解析为消息
 * 
 * @param json_str json串
 * @param len json串长度
 * @return Message* 解析完成的消息指针
 */
Message *app_message_initFromJson(char *json_str, size_t len)
{
    // 1.解析json串
    cJSON *root = cJSON_ParseWithLength(json_str,len);
    if (root == NULL)
    {
        log_warn("Json parse fail");
        goto JSON_PARSE_FAIL;
    }

    //2.申请消息的内存
    Message *msg = (Message *)malloc(sizeof(Message));
    if (msg == NULL)
    {
        log_error("Not enough memory");
        goto MSG_ALLOC_FAIL;
    }
    memset(msg, 0, sizeof(Message));

    //3.读取消息类型
    cJSON *connection_type_obj = cJSON_GetObjectItem(root, "connection_type");
    if (!cJSON_IsNumber(connection_type_obj))
    {
        log_warn("connection_type is not a number");
        goto JSON_NOT_VALID;
    }
    
    msg->type = connection_type_obj->valueint;

    //4.将id和msg的二进制字符串转化为二进制储存
    cJSON *id_obj = cJSON_GetObjectItem(root, "id");
    if (!cJSON_IsString(id_obj))
    {
        log_warn("id is not a string");
        goto JSON_NOT_VALID;
    }
    cJSON *msg_obj = cJSON_GetObjectItem(root, "msg");
    if (!cJSON_IsString(msg_obj))
    {
        log_warn("msg is not a string");
        goto JSON_NOT_VALID;
    }
    
    msg->id_len = strlen(id_obj->valuestring)/2;
    msg->len = strlen(msg_obj->valuestring)/2;

    msg->id = malloc(msg->id_len);
    if (!msg->id)   
    {
        log_error("Not enough memory");
        goto ID_ALLOC_FAIL;
    }
    msg->data = malloc(msg->len);
    if (!msg->data)
    {
        log_error("Not enough memory");
        goto DATA_ALLOC_FAIL;
    }

    app_message_str2hex(id_obj->valuestring, msg->id, msg->id_len);
    app_message_str2hex(msg_obj->valuestring, msg->data, msg->len);

    free(root);
    log_info("Init message from json success");
    return msg;
    
DATA_ALLOC_FAIL:
    free(msg->id);

ID_ALLOC_FAIL:
JSON_NOT_VALID:
    free(msg);

MSG_ALLOC_FAIL:
    cJSON_Delete(root);

JSON_PARSE_FAIL:
    return NULL;
}



/**
 * @brief 将一个消息转换为json字符串
 * 
 * @param msg 要转化的消息
 * @param json_str 输出的json字符串
 * @param len 输出的json字符串的缓冲区总长度
 * @return int 转换后的json字符串的长度  -1表示失败
 */
int app_message_saveAsJson(Message *msg, char *json_str, size_t len)
{
    //此方法会把消息转化为Json格式：我们会将消息的id和data转化为字符串表示的二进制
    if (!msg)
    {
        log_warn("message is null");
        return -1;
    }
    if (!json_str)
    {
        log_warn("json_str is null");
        return -1;
    }
    
    //使用cJSON库生成Json字符串
    cJSON *root = cJSON_CreateObject();
    if (!root)
    {
        log_warn("cJSON_CreateObject fail");
        goto JSON_CREATE_FAIL;
    }

    cJSON_AddNumberToObject(root, "connection_type", msg->type);
    //将msg中原始的二进制转化为二进制字符串，放入Json中
    char *id_str = app_message_hex2str(msg->id, msg->id_len);
    if (!id_str)
    {
        log_error("ID_Str Not enough memory");
        goto ID_STR_NEW_FAIL;
    }

    char *data_str = app_message_hex2str(msg->data, msg->len);
    if (!data_str)
    {
        log_error("Data_Str Not enough memory");
        goto DATA_STR_NEW_FAIL;
    }

    cJSON_AddStringToObject(root, "id", id_str);
    cJSON_AddStringToObject(root, "msg", data_str);
    char *tmp_str = cJSON_PrintUnformatted(root);
    if(strlen(tmp_str) >= len)
    {
        log_error("Out buffer not enough");
        goto OUT_BUFFER_NOT_ENOUGH;
    }
    strcpy(json_str, tmp_str);
    free(tmp_str);
    //使用完cJson后，释放内存
    cJSON_Delete(root);

    log_info("Save message to json success");
    return strlen(json_str) + 1;

OUT_BUFFER_NOT_ENOUGH:
    free(data_str);

DATA_STR_NEW_FAIL:
    free(id_str);
    
ID_STR_NEW_FAIL:
    cJSON_Delete(root);

JSON_CREATE_FAIL:
    return -1;
}

/**
 * @brief 将一个消息转换为二进制串
 * 
 * @param msg 要转化的消息
 * @param data 输出的二进制串指针
 * @param len 输出的二进制串的缓冲区总长度
 * @return int 转换后的二进制串的长度  -1表示失败
 */
int app_message_saveAsBinary(Message *msg, void *data, size_t len)
{
    //1. 首先校验输出的长度
    if (len < 3 + msg->id_len + msg->len)
    {
        log_warn("Out buffer not enough");
        return -1;
    }
    //2. 写入类型，id长度和内容长度
    memcpy(data,&msg->type, 1);
    memcpy(data + 1, &msg->id_len, 1);
    memcpy(data + 2, &msg->len, 1);
    //3. 写入id和内容
    memcpy(data + 3, msg->id, msg->id_len);
    memcpy(data + 3 + msg->id_len, msg->data, msg->len);
    log_info("Save message to binary success");
    return 3 + msg->id_len + msg->len;
}

/**
 * @brief 释放一个消息的内存
 * 
 * @param msg 要释放的消息指针
 */
void app_message_free(Message *msg)
{
    free(msg->id);
    free(msg->data);
    free(msg);
}













